<template>
  <div class="ai-dialogue">
    <div class="header">
      <span>
        <img src="https://blog-chen.oss-cn-shanghai.aliyuncs.com/favicon.ico" alt="">
        CsBlog-Ai</span>
      <span style="cursor: pointer;" @click="$store.dispatch('aiHide')">x</span>
    </div>
    <!-- 对话内容区域 -->
    <div class="dialogue-content" ref="dialogueContent">
      <!-- 作者发送的消息 -->
      <div v-for="(item,index) in chatResponses">
        <div class="author" :key="index">
          <div style="border-bottom: 1px solid rgba(170, 199, 251, 0.5);margin:5px 0 3px 0 ;">
            <span style="padding: 5px;">
              <img :src="item.user.avatar" alt="">
              {{item.user.userName}}
            </span>
          </div>
          <div style="color: white;padding:5px">
            {{item.user.content}}
          </div>
        </div>
        <div class="aiComment">
          <div class="top">
            <span style="padding: 5px;">
              {{item.chat.aiName}}
              <img :src="item.chat.avatar" alt="">
            </span>
          </div>
          <div style="color: rgb(20, 20, 20);padding:5px" v-html="contentMarked(item.chat.content.join(''))">
          </div>
        </div>
      </div>
    </div>

    <!-- 输入区域 -->
    <div class="input-area">
      <input type="text" v-model="userInput" placeholder="请输入您的问题..." @keyup.enter="sendMessage" />
      <div class="el-icon-position" @click="sendMessage" v-if="!iconLoing"></div>
      <div class="el-icon-video-play" @click="stopSSE" title="点击停止" v-if="iconLoing"></div>
    </div>
  </div>
</template>

<script>
  import axios from 'axios';
  import {
    marked
  } from 'marked'
  import prism from "prismjs";
  import { fetchEventSource } from '@microsoft/fetch-event-source';
  export default {
    name: 'AiDialogue',
    data() {
      return {
        userInput: '', // 用户输入的内容
        chatResponses: [],
        eventSource: null,
        userInputList: [],
        abortController: null,
        observer: null,
        iconLoing: false
      };
    },
    created() {
      // this.$bus.$on("sendAi", val => {
      //   this.userInput = val
      //   // this.sendMessage()
      // })
    },
    mounted() {
      if (this.$store.state.UserInfo.id != null || this.$store.state.UserInfo.username != '') {
        if (localStorage.getItem(this.$store.state.UserInfo.id) != undefined
          || localStorage.getItem(this.$store.state.UserInfo.id) != null) {
          let res = localStorage.getItem(this.$store.state.UserInfo.id)
          this.chatResponses = JSON.parse(res)
        }
      }
      this.observeContentChanges()
      this.$bus.$on("sendAi", val => {
        this.userInput = val
        this.sendMessage()
      })
    },
    watch: {
      chatResponses() {
        this.$nextTick(() => {
          prism.highlightAll();// 全局代码高亮
        });
      }
    },
    methods: {
      contentMarked(contents) {
        var reg = new RegExp("<pre", "g")
        var content = marked(contents)
        var str = content.replace(reg, `<pre class='line-numbers'`)
        return str
      },
      // 实时滚动到底部
      observeContentChanges() {
        const dialogueContent = this.$refs.dialogueContent;
        if (dialogueContent) {
          new MutationObserver(() => {
            // 滚动到底部
            dialogueContent.scrollTop = dialogueContent.scrollHeight;
          }).observe(dialogueContent, {
            childList: true,
            subtree: true
          });
        }
      },
      sendMessage() {
        if (this.userInput === '') {
          return; // 如果输入为空，则不发送
        }
        if (this.iconLoing) {
          this.userInput = ""
          return;
        }
        if (this.$store.state.UserInfo.id == null || this.$store.state.UserInfo.username == '') {
          this.$message.warning('请先登录再提问~')
          return
        }
        let user = this.$store.state.UserInfo
        // GEt发送请求
        // this.getChatCompletions()
        // post发送请求
        this.SendAi()
      },
      stopSSE() {
        if (this.abortController) {
          this.abortController.abort();
          this.iconLoing = false
          if (this.chatResponses.length != 0) {
            localStorage.setItem(user.id, JSON.stringify(this.chatResponses))
          }
        }
      },
      SendAi() {
        this.abortController = new AbortController();
        const signal = this.abortController.signal;
        console.log(signal);
        // 添加到数组中
        let user = this.$store.state.UserInfo
        let userObj = {
          user: {
            userName: user.nickname,
            avatar: user.avatar,
            content: this.userInput
          },
          chat: {
            avatar: "https://blog-chen.oss-cn-shanghai.aliyuncs.com/favicon.ico",
            aiName: "CsBlog-Ai",
            content: []
          }
        }
        this.chatResponses.push(userObj)
        let sendMsg = this.userInput.replace(/\s+/g, '')
        this.userInput = ''; // 清空输入框
        fetchEventSource(`${process.env.VUE_APP_AI_PATH}/completionsPostNew`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive'
          },
          body: JSON.stringify({ msg: sendMsg }),
          onmessage: (event) => {
            const chatResponse = JSON.parse(event.data);
            if (chatResponse.result.output.content.trim() != '') {
              // 获取最后有的数组
              let length = this.chatResponses.length
              this.chatResponses[length - 1].chat.content.push(chatResponse.result.output.content)
            }
          },
          onopen: (response) => {
            if (response.ok && response.headers.get('content-type') === 'text/event-stream') {
              this.iconLoing = true
              return; // 连接成功
            } else if (response.status >= 400 && response.status < 500 && response.status === 429) {
              this.abortController.abort();
              throw new Error('Client-side error');
            } else {
              this.abortController.abort();
              throw new Error('Retriable error');
            }
          },
          onerror: (event) => {
            if (event.target.readyState === EventSource.CLOSED) {
              console.error('Connection was closed by the server.');
            } else {
              console.error('Error occurred:', event);
            }
          },
          onclose: () => {
            if (this.chatResponses.length != 0) {
              localStorage.setItem(user.id, JSON.stringify(this.chatResponses))
            }
            this.$nextTick(() => {
              prism.highlightAll();// 全局代码高亮
              // 滚动到底部
              this.observeContentChanges()
            });
            this.iconLoing = false
            console.log('Connection closed.');
          },
          signal: signal
        });
      }
    },
    beforeDestroy() {
      if (this.abortController) {
        this.abortController.abort();
      }
    },
  };
</script>

<style scoped lang="less">
  .ai-dialogue {
    position: fixed;
    flex-direction: column;
    width: 450px;
    z-index: 1001;
    box-sizing: border-box;
    padding: 12px 24px 8px;
    align-items: flex-start;
    grid-gap: 12px;
    gap: 12px;
    right: 14px;
    bottom: 14px;
    top: calc(60px + 1.767rem);
    background-image: url(https://lf-web-assets.juejin.cn/obj/juejin-web/xitu_juejin_web/086a891665bdd751f339293cc0d75038.svg),
      url(https://lf-web-assets.juejin.cn/obj/juejin-web/xitu_juejin_web/img/bgc2.1e5526a.png),
      linear-gradient(173deg, #f4f9ff -24.94%, #edf1f9 103.15%);
    background-repeat: no-repeat;
    background-position: 100% 0;
    background-attachment: fixed;
    background-size: auto;
    border-radius: 4px;
    font-size: 12px;
    font-style: normal;
    font-weight: 400;
    line-height: 24px;
    letter-spacing: .039px;
    box-shadow: 0 32px 60px 0 rgba(81, 87, 103, .12);

    .header {
      display: flex;
      justify-content: space-between;
      width: 100%;
      align-items: center;

      span {
        font-size: 15px;
        font-weight: 700;

        img {
          width: 20px;
          height: 20px;
          vertical-align: sub;
        }
      }
    }

    .dialogue-content {
      height: 454px;
      margin-bottom: 12px;
      overflow-y: scroll;

      &::-webkit-scrollbar {
        display: none;
        /* 对于基于WebKit的浏览器 */
      }

      .author {
        width: 100%;
        min-width: 20px;
        /* border: 1px solid red; */
        margin: 5px 0;
        background-color: rgb(35, 147, 252);
        border-top-right-radius: 5px;
        border-bottom-right-radius: 5px;
        border-bottom-left-radius: 5px;

        span {
          font-size: 15px;
          font-weight: 700;

          img {
            width: 22px;
            height: 22px;
            vertical-align: sub;
            border-radius: 50%;
          }
        }
      }

      .aiComment {
        margin: 10px 0;
        width: 100%;
        min-width: 20px;
        background-color: rgb(220, 234, 248);

        border-top-left-radius: 5px;
        border-bottom-right-radius: 5px;
        border-bottom-left-radius: 5px;

        .top {
          display: flex;
          border-bottom: 1px solid rgba(170, 199, 251, 0.5);
          margin: 5px 0 3px 0;

          span {
            font-size: 15px;
            font-weight: 700;

            img {
              width: 22px;
              height: 22px;
              vertical-align: sub;
              border-radius: 50%;
            }
          }
        }

        /deep/ pre {
          background: rgb(121, 125, 125) !important;
        }

        /* /deep/ p code {
          padding: 5px;
          color: red;
          background-color: #f0f0f0;
        } */
      }
    }

    .input-area {
      position: fixed;
      display: flex;
      align-items: center;
      width: 390px;
      bottom: 26px;

      input {
        flex: 1;
        border: 1px solid #ccc;
        border-radius: 6px;
        padding: 8px;
      }

      /deep/ .el-icon-position {
        position: absolute;
        right: -22px;
        font-size: 20px;
        cursor: pointer;
      }

      /deep/ .el-icon-video-play {
        position: absolute;
        right: -22px;
        font-size: 20px;
        cursor: pointer;
      }

    }

    .bubble {
      max-width: 80%;
      padding: 8px;
      margin-bottom: 8px;
      border-radius: 4px;
      background-color: #f4f9ff;

      &.user {
        background-color: #edf1f9;
        align-self: flex-end;
      }
    }
  }
</style>